package com.cloudfun.campusshare.service.impl;

import cn.hutool.json.JSONUtil;
import com.cloudfun.campuscontract.RemoteTradeInfoChainService;
import com.cloudfun.campuscontract.dto.TradeInfoDTO;
import com.cloudfun.campusshare.common.constant.BaseConstant;
import com.cloudfun.campusshare.common.constant.Code;
import com.cloudfun.campusshare.common.constant.KjtServiceType;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.common.model.dto.BasePayDTO;
import com.cloudfun.campusshare.common.model.dto.kjt.*;
import com.cloudfun.campusshare.configuration.property.KjtProperties;
import com.cloudfun.campusshare.configuration.property.WeChatProperties;
import com.cloudfun.campusshare.entity.OrderEntity;
import com.cloudfun.campusshare.entity.OrderRefundEntity;
import com.cloudfun.campusshare.service.KjtPayeeSelector;
import com.cloudfun.campusshare.service.KjtService;
import com.cloudfun.campusshare.service.PayService;
import com.cloudfun.campusshare.service.UserAuthService;
import com.cloudfun.campusshare.util.AmountUtil;
import com.cloudfun.campusshare.util.NetUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Huqin on 2020/7/31
 */
@Slf4j
@Service
public class KjtPayServiceImpl implements PayService {

    @Autowired
    private WeChatProperties weChatProperties;

    @Autowired
    private KjtProperties kjtProperties;

    @Autowired
    private UserAuthService userAuthService;

    @Autowired
    private KjtService kjtService;

    @Autowired
    private KjtPayeeSelector payeeSelector;

    @Reference(timeout = 10_000)
    private RemoteTradeInfoChainService remoteTradeInfoChainService;

    @Override
    public boolean support(OrderEntity orderEntity) {
        // 支持非0元订单
        return !NumberUtils.INTEGER_ZERO.equals(orderEntity.getSettlementAmount());
    }

    @Override
    public BasePayDTO payOrder(OrderEntity orderEntity) {
        KjtInstantTradeReqDTO reqDTO = this.buildReqDTO(orderEntity);
        KjtAggregatePaymentDto respDTO = kjtService.execute(reqDTO, KjtServiceType.INSTANT_TRADE,
                new ParameterizedTypeReference<KjtBaseResponseDTO<KjtAggregatePaymentDto>>() {
                });
        if (StringUtils.equals(respDTO.getStatus(), "F")) {
            throw new BusinessException(Code.ERROR, respDTO.getMemo());
        }
        // 数据上链
        this.payTradeInfoUpload2BlockChain(reqDTO.getTradeInfo());
        log.info("快捷通聚合支付:{}", JSONUtil.parseObj(respDTO).toStringPretty());
        KjtPayDTO kjtPayDTO = new KjtPayDTO();
        kjtPayDTO.setOrderId(orderEntity.getId());
        kjtPayDTO.setOrderNo(orderEntity.getOrderNo());
        kjtPayDTO.setReturnUrl(respDTO.getReturnUrl());
        return kjtPayDTO;
    }

    /**
     * 退款
     *
     * @param refundEntity
     */
    @Override
    public void refund(OrderRefundEntity refundEntity) {
        KjtInstantTradeRefundDTO refundDTO = this.buildTradeRefund(refundEntity);
        KjtAggregatePaymentDto respDTO = kjtService.execute(refundDTO, KjtServiceType.TRADE_REFUND,
                new ParameterizedTypeReference<KjtBaseResponseDTO<KjtAggregatePaymentDto>>() {
                });
        if (StringUtils.equals(respDTO.getStatus(), "F")) {
            throw new BusinessException(Code.ERROR, respDTO.getMemo());
        }
        log.info("快捷通聚合支付:{}", JSONUtil.parseObj(respDTO).toStringPretty());
    }

    /**
     * 支付数据上链
     *
     * @param instantTradeInfoDTO
     */
    private void payTradeInfoUpload2BlockChain(KjtInstantTradeInfoDTO instantTradeInfoDTO) {
        BaseConstant.SCHEDULED_EXECUTOR.execute(() -> {
            TradeInfoDTO tradeInfoDTO = new TradeInfoDTO();
            BeanUtils.copyProperties(instantTradeInfoDTO, tradeInfoDTO);
            tradeInfoDTO.setOrderNo(instantTradeInfoDTO.getOutTradeNo());
            remoteTradeInfoChainService.add(tradeInfoDTO);
        });
    }

    /**
     * 构造支付请求对象
     *
     * @param orderEntity
     * @return
     */
    private KjtInstantTradeReqDTO buildReqDTO(OrderEntity orderEntity) {
        KjtInstantTradeReqDTO tradeReqDTO = new KjtInstantTradeReqDTO();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        tradeReqDTO.setPayerIp(NetUtil.getClientIp(request));
        tradeReqDTO.setPayMethod(this.buildPayMethod(orderEntity));
        tradeReqDTO.setTimeoutExpress("10m");
        tradeReqDTO.setTradeInfo(this.buildTradeInfo(orderEntity));
        Map<String, String> terminalInfo = new HashMap<>();
        terminalInfo.put("terminal_type", "01"); //固定为手机
        terminalInfo.put("ip", NetUtil.getLocalIp());// 本机ip
        tradeReqDTO.setTerminalInfo(terminalInfo);
        tradeReqDTO.setReturnUrl(String.format(kjtProperties.getReturnUrl(),orderEntity.getDeviceEntity().getImei(),orderEntity.getId()));
        return tradeReqDTO;
    }

    /**
     * 构造交易信息
     *
     * @param orderEntity
     * @return
     */
    private KjtInstantTradeInfoDTO buildTradeInfo(OrderEntity orderEntity) {
        KjtInstantTradeInfoDTO tradeInfoDTO = new KjtInstantTradeInfoDTO();
        tradeInfoDTO.setOutTradeNo(orderEntity.getOrderNo());
        tradeInfoDTO.setSubject(orderEntity.getOrderName());
        String amount = AmountUtil.amountRoundStr(orderEntity.getSettlementAmount(), 2);
        tradeInfoDTO.setPrice(amount);
        tradeInfoDTO.setQuantity("1");
        tradeInfoDTO.setTotalAmount(amount);
        String payeeIdentityId = payeeSelector.select(orderEntity.getUserId());
        tradeInfoDTO.setPayeeIdentity(payeeIdentityId);
        tradeInfoDTO.setNotifyUrl(kjtProperties.getNotifyUrl());
        return tradeInfoDTO;
    }

    /**
     * 退款数据
     * @param refundEntity
     * @return
     */
    private KjtInstantTradeRefundDTO buildTradeRefund(OrderRefundEntity refundEntity) {
        KjtInstantTradeRefundDTO refundDTO = new KjtInstantTradeRefundDTO();
        refundDTO.setOutTradeNo(refundEntity.getOrderRefundNo());
        refundDTO.setOrigOutTradeNo(refundEntity.getOrderNo());
        String amount = AmountUtil.amountRoundStr(refundEntity.getPrice(), 2);
        refundDTO.setRefundAmount(amount);
        refundDTO.setNotifyUrl(kjtProperties.getNotifyUrl());
        return refundDTO;
    }

    /**
     * 构造支付方式
     *
     * @param orderEntity
     * @return
     */
    private KjtMiniProgramPayMethodDTO buildPayMethod(OrderEntity orderEntity) {
        KjtMiniProgramPayMethodDTO payMethodDTO = new KjtMiniProgramPayMethodDTO();
        payMethodDTO.setPayProductCode("83");
        payMethodDTO.setAmount(AmountUtil.amountRoundStr(orderEntity.getPrice(), 2));
//        payMethodDTO.setTargetOrganization(PayOrganization.WECHAT.name());// 写死为微信支付
//        payMethodDTO.setAppId(weChatProperties.getAppId());
//        UserAuthEntity userAuthEntity = userAuthService.getByUserIdAndType(AuthenticationHolder.getUserId(), IdentityType.WE_CHAT);
//        payMethodDTO.setOpenId(userAuthEntity.getIdentifier());
        return payMethodDTO;
    }

}